/**
 * This is the main template function
 */
function publish (fileGroup, context) {
   
   // Quit if no destination
	if (!context.d) { return; }
	
	// Get an ordered list of the jsFiles
	var files = fileGroup.files;
	
	// Build the config object
	var config     = isset(context.config) ? context.config : {};
	
	config.indexFile = isset(config.indexFile)   ? config.indexFile   : null;
	config.link   = isset(config.link)   ? config.link   : '..';
	config.title   = isset(config.title)   ? config.title   : 'JsDoc';
	config.pages   = isset(config.pages)   ? config.pages   : [];
	config.version = isset(config.version)   ? config.version   : "0.0.1";
	config.copyright   = isset(config.copyright)   ? config.copyright   : 'copyright';
	
	/**
	 * Build the data object which will be passed to 
	 * the template files.
	 */
	var tplInfos = { 
	   config: config,
	   // Contains file informations
	   files: [], 
	   // List of all classes
	   libclasses: [],
	   // List of all symbols
	   symbolList: []
	};
	
	linkToType.classfiles = [];
	var subclasses = [];
	var parentClasses = [];
	
	// For each javascript file, generate the _file.html and the _src.html
	for (var i = 0 ; i < files.length; i++) {
	   
		var name = (files[i].overview.name || files[i].filename);
		tplInfos.files[i] = {
		   path        : files[i].path,
			name        : name,
			file        : name+'.html',
			desc        : files[i].overview.desc
		};
		
		// Generate a list of class
		for (var j = 0, jx = files[i].symbols.length; j < jx; j++) {
			var symbol = files[i].symbols[j];
			tplInfos.symbolList.push(symbol);
			if(symbol.isa == 'CONSTRUCTOR') {
			   tplInfos.libclasses.push({file: symbol.alias+'.html', name: symbol.alias, classSymbol: symbol });
         	linkToType.classfiles.push(symbol.alias+'.html');
         	
         	parentClasses[symbol.alias] = "Object";
         	
         	// Build the subclass array
         	if(symbol.augments && symbol.augments.length > 0 ) {
            	for(var k = 0 ; k < symbol.augments.length ; k++) {
            	   
                  if(!subclasses[symbol.augments[k]]) { subclasses[symbol.augments[k]] = []; }
            	   subclasses[symbol.augments[k]].push(symbol.alias);
            	   
            	   parentClasses[symbol.alias] = symbol.augments[k];
            	   
            	}
         	}
         	
			}
		}
	}
	
	// Sort classes and files by name
	function byName(a, b) {
		if (a.name != undefined && b.name != undefined) {
			a = a.name.toLowerCase();
			b = b.name.toLowerCase();
			if (a < b) return -1;
			if (a > b) return 1;
			return 0;
		}
	}
	tplInfos.libclasses.sort(byName);
	tplInfos.files.sort(byName);
	
	// Templates :
   var jsTpl = new JsPlate(context.t + 'jsFile.tpl');
   var classTpl = new JsPlate(context.t + 'class.tpl');
   var pageTpl = new JsPlate(context.t + 'page.tpl');
   
   var layoutTpl = new JsPlate(context.t + 'layout.tpl');

   // Process the "jsFiles" templates
	for (var i = 0 ; i < tplInfos.files.length; i++) {
	   // Read the source file:
	   var jsTplData = {
	      code: IO.readFile(tplInfos.files[i].path),
	      sourceFileName: tplInfos.files[i].name  
	   };
   	tplInfos.layoutContent = jsTpl.process(jsTplData);
      tplInfos.title = tplInfos.files[i].name;
	   IO.saveFile(context.d, tplInfos.files[i].file , layoutTpl.process(tplInfos));
   }
   
   // Process the "class" templates
	for (var i = 0 ; i < tplInfos.libclasses.length; i++) {
	   
	   var thisClass = tplInfos.libclasses[i].classSymbol;
		// sort inherited methods by class
		var inheritedMethods = thisClass.getInheritedMethods();
		if (inheritedMethods.length > 0) {
			thisClass.inherited = {};
			for (var n = 0; n < inheritedMethods.length; n++) {
				if (! thisClass.inherited[inheritedMethods[n].memberof]) thisClass.inherited[inheritedMethods[n].memberof] = [];
				thisClass.inherited[inheritedMethods[n].memberof].push(inheritedMethods[n]);
			}
		}
   	thisClass.name = tplInfos.libclasses[i].classSymbol.alias;
		if(subclasses[thisClass.name]) {
		   thisClass.subclasses = subclasses[thisClass.name];
		}
      tplInfos.layoutContent = classTpl.process([thisClass]);
      tplInfos.title = thisClass.name;
   	
   	IO.saveFile(context.d, tplInfos.libclasses[i].name+'.html' , layoutTpl.process(tplInfos) );
   }
	
	// Process the pages template
	for(var i = 0 ; i < config.pages.length ; i++) {
	   var page = config.pages[i];
      tplInfos.pageContent = IO.readFile(page.src);
   	tplInfos.layoutContent = pageTpl.process(tplInfos);
      tplInfos.title = page.title;
   	IO.saveFile(context.d,  page.file , layoutTpl.process(tplInfos) );
	}
	
	
	// Build the treeview page
   var displayTree = function(cl) {
      var ret = (cl == "Object") ? "<ul>" : "<a href='"+cl+".html'>"+cl+"</a><ul>";
      for(c in parentClasses) {
         if( parentClasses.hasOwnProperty(c) ) {
            if(parentClasses[c] == cl) {
      	      ret+= "<li>"+displayTree(c)+"</li>";
   	      }
         }
      }
      return ret+"</ul>";
   };
	tplInfos.pageContent = "<h1>Class Hierarchy</h1>"+displayTree('Object');
	tplInfos.layoutContent = pageTpl.process(tplInfos);
   tplInfos.title = 'Class Tree View';
	IO.saveFile(context.d,  'treeview.html', layoutTpl.process(tplInfos) );
	
	
	// Copy static files into destination folder
   copyDirectory('css', context);
   copyDirectory('js', context);
}



function copyDirectory(dir, context) {
   IO.makeDir(context.d + dir);
	var folderFiles = IO.ls([context.t + dir]);
	for (var i = 0 ; i < folderFiles.length; i++) {
		IO.copyFile(folderFiles[i], context.d + dir);
	}
}


function isset (val) {
	return (typeof(val) != 'undefined') && (val != null);
}

/**
	Takes a string of object types and adds links if there exists
	any documentation files in the output for that type.
	@param typeString Like "Foo" or "Foo[] | Bar".
 */
function linkToType(typeString) {
	var sep = /[^a-zA-Z0-9._$]+/;
	var types = typeString.split(sep);
	
	for (var i = 0; i < types.length; i++) {
		var link = linkToType.classfiles[types[i]];
		if (link) {
			var re = new RegExp('(^|[^a-zA-Z0-9._$])'+types[i]+'($|[^a-zA-Z0-9._$])');
			typeString = typeString.replace(re, "$1<a href=\""+link+"\">"+types[i]+"</a>$2", "g");
		}
	}
	
	return typeString;
}